"""
Redis客户端管理
"""
import asyncio
from typing import Optional, Any, Dict, List
import redis.asyncio as redis
import orjson

from app.config import get_settings
from app.utils.logger import get_logger

settings = get_settings()
logger = get_logger(__name__)

# 系统前缀
SYSTEM_PREFIX = "kmsg_ui"

# 全局Redis连接池
_redis_pool: Optional[redis.Redis] = None


async def get_redis_client() -> redis.Redis:
    """获取Redis客户端"""
    global _redis_pool
    
    if _redis_pool is None:
        try:
            _redis_pool = redis.from_url(
                settings.redis.url,
                max_connections=settings.redis.max_connections,
                retry_on_timeout=True,
                socket_keepalive=True,
                socket_keepalive_options={},
                health_check_interval=30
            )
            logger.info(f"Redis连接池创建成功: {settings.redis.host}:{settings.redis.port}")
        except Exception as e:
            logger.error(f"Redis连接失败: {e}")
            raise
    
    return _redis_pool


def _add_prefix(key: str) -> str:
    """为key添加系统前缀（如果key不是以系统前缀开头）"""
    if key.startswith(f"{SYSTEM_PREFIX}:"):
        return key
    return f"{SYSTEM_PREFIX}:{key}"


def _remove_prefix(key: str) -> str:
    """移除key的系统前缀"""
    if key.startswith(f"{SYSTEM_PREFIX}:"):
        return key[len(f"{SYSTEM_PREFIX}:"):]
    return key


async def close_redis_client():
    """关闭Redis连接"""
    global _redis_pool

    if _redis_pool:
        await _redis_pool.close()
        _redis_pool = None
        logger.info("Redis连接已关闭")


class RedisManager:
    """Redis管理器"""

    def __init__(self):
        self.client: Optional[redis.Redis] = None

    async def get_client(self) -> redis.Redis:
        """获取Redis客户端"""
        if self.client is None:
            self.client = await get_redis_client()
        return self.client
    
    async def ping(self) -> bool:
        """检查Redis连接"""
        try:
            client = await self.get_client()
            await client.ping()
            return True
        except Exception as e:
            logger.error(f"Redis ping失败: {e}")
            return False
    
    async def set_json(self, key: str, value: Any, ttl: Optional[int] = None) -> bool:
        """存储JSON数据"""
        try:
            client = await self.get_client()
            prefixed_key = _add_prefix(key)
            json_data = orjson.dumps(value)

            if ttl:
                await client.setex(prefixed_key, ttl, json_data)
            else:
                await client.set(prefixed_key, json_data)
            
            return True
        except Exception as e:
            logger.error(f"Redis set_json失败: {e}")
            return False
    
    async def get_json(self, key: str, default: Any = None) -> Any:
        """获取JSON数据"""
        try:
            client = await self.get_client()
            prefixed_key = _add_prefix(key)
            data = await client.get(prefixed_key)

            if data is None:
                return default

            return orjson.loads(data)
        except Exception as e:
            logger.error(f"Redis get_json失败: {e}")
            return default

    async def delete(self, *keys: str) -> int:
        """删除键"""
        try:
            client = await self.get_client()
            prefixed_keys = [_add_prefix(key) for key in keys]
            return await client.delete(*prefixed_keys)
        except Exception as e:
            logger.error(f"Redis delete失败: {e}")
            return 0

    async def exists(self, key: str) -> bool:
        """检查键是否存在"""
        try:
            client = await self.get_client()
            prefixed_key = _add_prefix(key)
            return bool(await client.exists(prefixed_key))
        except Exception as e:
            logger.error(f"Redis exists失败: {e}")
            return False

    async def expire(self, key: str, ttl: int) -> bool:
        """设置过期时间"""
        try:
            client = await self.get_client()
            prefixed_key = _add_prefix(key)
            return bool(await client.expire(prefixed_key, ttl))
        except Exception as e:
            logger.error(f"Redis expire失败: {e}")
            return False

    async def hset(self, name: str, mapping: Dict[str, Any]) -> int:
        """设置哈希表"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            # 将值转换为JSON字符串
            json_mapping = {k: orjson.dumps(v) for k, v in mapping.items()}
            return await client.hset(prefixed_name, mapping=json_mapping)
        except Exception as e:
            logger.error(f"Redis hset失败: {e}")
            return 0
    
    async def hget(self, name: str, key: str, default: Any = None) -> Any:
        """获取哈希表字段"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            data = await client.hget(prefixed_name, key)

            if data is None:
                return default

            return orjson.loads(data)
        except Exception as e:
            logger.error(f"Redis hget失败: {e}")
            return default

    async def hgetall(self, name: str) -> Dict[str, Any]:
        """获取哈希表所有字段"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            data = await client.hgetall(prefixed_name)

            # 将字节数据转换为JSON
            result = {}
            for k, v in data.items():
                try:
                    result[k.decode()] = orjson.loads(v)
                except:
                    result[k.decode()] = v.decode()

            return result
        except Exception as e:
            logger.error(f"Redis hgetall失败: {e}")
            return {}

    async def lpush(self, name: str, *values: Any) -> int:
        """列表左侧推入"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            json_values = [orjson.dumps(v) for v in values]
            return await client.lpush(prefixed_name, *json_values)
        except Exception as e:
            logger.error(f"Redis lpush失败: {e}")
            return 0

    async def lrange(self, name: str, start: int, end: int) -> List[Any]:
        """获取列表范围"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            data = await client.lrange(prefixed_name, start, end)

            result = []
            for item in data:
                try:
                    result.append(orjson.loads(item))
                except:
                    result.append(item.decode())

            return result
        except Exception as e:
            logger.error(f"Redis lrange失败: {e}")
            return []

    async def ltrim(self, name: str, start: int, end: int) -> bool:
        """修剪列表"""
        try:
            client = await self.get_client()
            prefixed_name = _add_prefix(name)
            await client.ltrim(prefixed_name, start, end)
            return True
        except Exception as e:
            logger.error(f"Redis ltrim失败: {e}")
            return False


# 全局Redis管理器实例
redis_manager = RedisManager()
